home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d3
/
cmdedit.arc
/
CMDSRC.ARC
/
EDIT.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-08-15
|
24KB
|
970 lines
; EDIT.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; This module contains the line editing functions of CMDEDIT.
PUBLIC get_kbd_line
PUBLIC auto_recall
PUBLIC expand_fnkey
INCLUDE common.inc
INCLUDE ascii.inc
INCLUDE BIOS.INC
INCLUDE DOS.INC
INCLUDE GENERAL.INC
CSEG SEGMENT PARA PUBLIC 'CODE'
CSEG ENDS
DGROUP GROUP CSEG
ASSUME CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:DGROUP
CSEG SEGMENT PARA PUBLIC 'CODE'
EXTRN linebuf:BYTE
EXTRN lastchar:WORD
EXTRN caller_cursor:WORD
EXTRN dot:WORD
EXTRN edit_mode:BYTE
EXTRN omode_cursor:WORD
EXTRN sym_stk:WORD
EXTRN LINEBUF_END:ABS
tempchar db ? ;Temporary storage
auto_recall db 0 ;By default no auto recall
auto_recall_on db ? ;1 if auto-recall in effect,
; else 0
continue_recall db ? ;auto-recall state variable
fnkey_tab db 'S','F',0 ;Used to look for function key
; definitions.
fnkey_exec_char db '@' ;If the last character a fn key
; definition is this, the key is
; executed immediately
; Must be IDENTICAL to the string in CMDCONF.C including the
; terminating '\0' byte. This must be followed immediately by ctrl_key_defs.
cmdedit_keymap_id db 'CMDEDIT key map',0
; ctrl_key_redefs is used to allow the cmdconf program to remap the control
; keys. Each entry corresponds to a control key. It must immediately follow
; cmdedit_keymap_id.
ctrl_key_redefs LABEL WORD
x = 0
REPT 32 ;32 control keys
DW x
x = x + 1
ENDM
EXTRN disp_line:PROC
EXTRN hist_back:PROC
EXTRN hist_fwd:PROC
EXTRN hist_bck_match:PROC
EXTRN hist_fwd_match:PROC
EXTRN remember:PROC
EXTRN execute_auto_recall:PROC
EXTRN insert_at_dot:PROC
EXTRN erase_to_dot:PROC
EXTRN isalphnum:PROC
EXTRN set_disp_marks:PROC
EXTRN bell:PROC
EXTRN line_to_scr:PROC
EXTRN isspace:PROC
EXTRN xlate_lower:PROC
EXTRN expand_var:PROC
EXTRN ismacsym:PROC
EXTRN get_symbol:PROC
;number of command keys
NUM_CMD_KEYS EQU (cmd_key_jumps-cmd_key_table)/2
;+
; FUNCTION : get_kbd_line
;
; Gets a line from the user and stores it in linebuf. The length
; of the line is stored in global linelen. The name is a misnomer
; because the line is from standard input, not necessarily from
; the keyboard.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
get_kbd_line proc near
@save si,di
mov al,auto_recall
mov auto_recall_on,al ;Indicate if auto-recall is enabled
mov continue_recall,1 ;Init auto-recall memory
; Main editing loop
@get_kbd_line_10:
mov al,continue_recall
and auto_recall_on,al ;Indicate if we should keep
; auto-recalling
mov continue_recall,0 ;Reset the flag. It will be set
; for the default actions keys.
call near ptr disp_line ;Show current line
call near ptr getkey ;get next key from the user
mov si,ax ;si holds the character
cmp ax,32 ;Control character ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,si ;DI used to calculate
add di,di ; offset into table
mov ax,ctrl_key_redefs[di] ;Mapping of key
mov si,ax
cmp ax,32 ;Control char ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,si ;DI used to calculate
add di,di ; offset into table
jmp ctrl_key_table[di] ;Branch according to control char
@get_kbd_line_15: ;Check if function key
cmp ax,256+59 ;>= F1 ?
jb @get_kbd_line_20 ;No, then check next table
cmp ax,256+68 ;<= F10
jg @get_kbd_line_20 ;Not fn key
jmp @fn_key ;Handle the function key
@get_kbd_line_20:
cmp ax,256+84 ;>= Shift-F1 ?
jb @get_kbd_line_25 ;No, then check next table
cmp ax,256+93 ;<= Shift-F10
jg @get_kbd_line_25 ;
jmp @sfn_key ;Handle the shifted function key
@get_kbd_line_25:
mov cx,NUM_CMD_KEYS ;size and...
mov bx,offset DGROUP:cmd_key_table ;beginning of jump table
@get_kbd_line_30: ;Loop begin
cmp ax,cs:[bx] ;Is this the key ?
je @get_kbd_line_40 ;Hurrah, found
inc bx ;point to next key
inc bx
loop @get_kbd_line_30 ;If more keys, repeat
jmp short @default_action ;key not in table
@get_kbd_line_40: ;Jump to location associated with
jmp word ptr cs:[bx+(2*NUM_CMD_KEYS)] ;key
@quote: ;Insert next char
; without interpreting it
call near ptr getkey
@default_action: ;Insert the character (in AX)
call near ptr store_char
jc @get_kbd_line_10 ;No room for char, keep looping
mov al,auto_recall_on ;Are we auto-recalling ?
or al,al
jz @get_kbd_line_10 ;No
call near ptr execute_auto_recall
jc @get_kbd_line_10 ;If carry set, no matching
; string in history buffer
mov continue_recall,1 ;Else indicate auto-recall is
; still to go on
jmp short @get_kbd_line_10
@char_left: ;Cursor one char left
call near ptr char_left ;char_left will return to top
jmp @get_kbd_line_10
; of editing loop
@char_right: ;Cursor one char right
call near ptr char_right ;char_right will return to top
jmp @get_kbd_line_10
; of editing loop
@word_left: ;Cursor one word left
call near ptr word_left
jmp @get_kbd_line_10
@word_right: ;Cursor one word right
call near ptr word_right
jmp @get_kbd_line_10
@bol: ;Beginning of line
call near ptr go_bol
jmp @get_kbd_line_10
@eol: ;End of line
call near ptr go_eol
jmp @get_kbd_line_10
@prev_line: ;Get previous history line
mov ax,offset DGROUP:hist_back
@history_line:
call ax
mov ax,lastchar
mov dot,ax ;Leave cursor at end of line
@history_search:
jnc @history_line_done ;Line found
call near ptr bell ;No line
@history_line_done:
jmp @get_kbd_line_10
@next_line: ;Get next history line
mov ax,offset DGROUP:hist_fwd
jmp short @history_line
@search_back: ;Search back thru history buffer
mov ax,offset DGROUP:hist_bck_match
@search:
mov di,dot ;Save current dot
call ax
mov dot,di ;Restore it
jmp short @history_search
@search_forw: ;Search forward thru history buffer
mov ax,offset DGROUP:hist_fwd_match
jmp short @search
@filename: ;Try to find a matching filename
call near ptr match_file
cmp auto_recall_on,1 ;Autorecall ongoing?
je short @del_eol ;Yes, then delete to end of line
jmp @get_kbd_line_10
@del_left: ;Delete char before cursor
mov ax,offset dgroup:char_left
jmp short @delete
@del_right: ;Delete char at cursor
mov ax,offset dgroup:char_right
jmp short @delete
@del_prev_word: ;Delete upto word beginning
mov ax,offset dgroup:word_left
jmp short @delete
@del_next_word: ;Delete to start of next word
mov ax,offset dgroup:word_right
jmp short @delete
@del_bol: ;Delete to beginning of line
mov ax,offset dgroup:go_bol
jmp short @delete
@toggle_insert:
mov ax,1
xor al,edit_mode ;Toggle edit mode
mov edit_mode,al
xchg ax,bx
add bx,bx ;Word offset
mov cx,omode_cursor[bx] ;cx<-cursor shape
mov ah,01h ;Set cursor size function
IF TOGGLE_CURSOR
int 10h ;BIOS
ENDIF
jmp @get_kbd_line_10 ;Repeat editing loop
@abort_and_store: ;Erases current line but remembers
; it in the history buffer
call near ptr remember
; Fall through to erase line
@erase_line:
call near ptr go_bol ;Move dot to beginning of line
; fall thru to delete to end of line
@del_eol: ;Delete to end of line
mov ax,offset dgroup:go_eol
@delete: ;General purpose delete
mov si,dot ;Remember the dot
call ax ;Move dot to new position
xchg si,ax
call near ptr erase_to_dot ;Delete characters between ax and dot
jmp @get_kbd_line_10
@autorecall:
xor auto_recall,1 ;Toggle auto recall mode
jmp @get_kbd_line_10
@vars:
; Expand the variables on the line.
call near ptr expand_var
jmp @get_kbd_line_10 ;Ignore return status from expand_var
@inline_back:
@inline_forw:
@ignore:
jmp @get_kbd_line_10 ;Ignore the character
ctrl_key_table LABEL WORD
dw @ignore ;NUL or ^@
dw @bol ;^A
dw @char_left ;^B
dw @ignore ;^C
dw @del_right ;^D
dw @eol ;^E
dw @char_right ;^F
dw @abort_and_store ;^G
dw @del_left ;^H
dw @filename ;^I
dw @vars ;^J might have to be @ignore in order for input
; redirection to work properly but try for
; var expansion anyway.
dw @del_eol ;^K
dw @del_prev_word ;^L
dw @done_editing ;^M
dw @next_line ;^N
dw @del_eol_exec ;^O
dw @ignore ;^P - don't use, filtered by get key call ?
dw @quote ;^Q
dw @search_back ;^R
dw @ignore ;^S - don't use, does not work properly
dw @ignore ;^T
dw @prev_line ;^U
dw @search_forw ;^V
dw @del_next_word ;^W
dw @del_bol ;^X
dw @autorecall ;^Y
dw @default_action ;^Z
dw @erase_line ;^[ or ESC
dw @inline_back ;^\
dw @inline_forw ;^]
dw @done_wipeout ;^^
dw @ignore ;^_
cmd_key_table: ;table of command keys
dw 127 ;DEL
dw 327 ;HOME
dw 328 ;UP
dw 331 ;LEFT
dw 333 ;RIGHT
dw 335 ;END
dw 336 ;DOWN
dw 338 ;INS
dw 339 ;KDEL
dw 371 ;CTLLEFT
dw 372 ;CTLRIGHT
cmd_key_jumps:
dw @del_left ;DEL
dw @bol ;HOME
dw @prev_line ;UP
dw @char_left ;LEFT
dw @char_right ;RIGHT
dw @eol ;END
dw @next_line ;DOWN
dw @toggle_insert ;INS
dw @del_right ;KDEL
dw @word_left ;CTLLEFT
dw @word_right ;CTLRIGHT
@sfn_key:
; A shifted function key has been struck.
; (Treat same as an unshifted function key).
@fn_key:
; A function key has been struck.
call near ptr expand_fnkey
jc @fn_key_20 ;Error or no expansion
or dx,dx ;Line to be executed
; immediately ?
je short @done_editing_2 ;Yes, all done
@fn_key_20:
jmp @get_kbd_line_10 ;else keep editing
@del_eol_exec: ;Deletes characters from the dot
; to end of the line and then
; executes the line
mov si,dot ;Remember the dot
call go_eol
xchg si,ax
call near ptr erase_to_dot
jmp short @done_editing
@done_wipeout:
; The line is executed. However it is not stored in the history buffer and
; is also removed from the screen (this is a little klugy).
mov ax,offset DGROUP:linebuf
mov dot,ax
mov dx,lastchar
mov lastchar,ax ;Temporarily pretend line
; is empty
xchg ax,dx
push ax
call near ptr set_disp_marks
call disp_line
pop ax
mov lastchar,ax ;Restore line length
jmp short @get_kbd_line_90
@done_editing:
call near ptr remember ;Store in history buffer
; Picks up line from global linebuf
@done_editing_2:
call near ptr disp_line ;Necessry for @del_eol_exec,
; might as well do for others
mov ax,lastchar
mov dot,ax ;Set dot to end of line
call near ptr line_to_scr ;Set cursor beyond last character
@get_kbd_line_90:
@DispCh CR ;Do a carraige return because
; some applications like EDLIN
; only do a LF to go to next line
; @DispCh LF ;Go onto next line
; all done
@get_kbd_line_99:
@restore
ret
get_kbd_line endp
getkey proc near
@GetKey 0
mov ah,0
or al,al
jne @114 ;not '\0'
mov ah,0Bh
int 21h ;check if key available
or al,al
jz @113 ;no character available
@GetKey 0
mov ah,1
jmp short @114
@113:
xor ax,ax
@114:
ret
getkey endp
;+
; FUNCTION : expand_fnkey
;
; Inserts the expansion corresponding to a symbol key into the
; linebuffer. If the buffer is too small, only as many characters as
; possible are inserted and the function returns an error. The
; function also returns an error if the symbols is not defined. The
; function also updates the displayed line. The function also checks
; if the line is to be executed immediately or not, based on the last
; character of the fn key expansion.
;
; Parameters:
; AX = function key character, must be between (256+59)-(256+68)
; function keys and (256+84)-(256+93) for shifted functin keys.
;
; Returns:
; CF = 0 if no error, else 1
; If CF is 1, then AX is 0 if symbol not found or non-zero
; if symbol found but no room in line.
; AX = 1 if symbol was present
; 0 if symbol was not found.
; DX = 0 if the line is to be executed immediately
; non-0 otherwise
; DX is only valid if CF=0 and AX=1
; Register(s) destroyed:
; <TBA>
;-
expand_fnkey proc near
@save si,di
push bp
mov bp,sp
sub sp,LINEBUF_SIZE
exp_buf equ <byte ptr [bp-LINEBUF_SIZE]>
mov si,offset DGROUP:fnkey_tab ;SI->'SFn'
mov dx,3 ;DX<-length of string
mov di,si
sub ax,256+59
cmp ax,10 ;Is it a function key
jnb @expand_fnkey_10 ;No, shifted function key
inc si ;SI->'Fn'
dec dx ;length of string is 2
jmp short @expand_fnkey_15
@expand_fnkey_10:
sub ax,84-59
@expand_fnkey_15:
cmp ax,9 ;F10 must appear as F0
jne @expand_fnkey_20
mov al,'0'-'1'
@expand_fnkey_20:
add al,'1'
mov 2[di],al ;Store in 'SFn' string
; OK now try and expand the symbol.
; SI->symbol
mov ax,LINEBUF_SIZE
xchg ax,dx ;AX<-length of synbol
; DX<-length of expansion buffer
lea di,exp_buf
call near ptr get_symbol ;Params SI,AX,DI,DX
jc @expand_fnkey_99 ;No symbol (buffer too
; small case not possible).
; AX will be 0 for this case.
; OK now we have the symbol expansion, so try insert it into the linebuffer.
; AX contains length of expansion
mov si,di ;SI->expansion
add di,ax
dec di ;DI->last char of expansion
xor dx,dx
mov dl,byte ptr [di]
sub dl,fnkey_exec_char ;Is this line to be
; immediately executed
jne @expand_fnkey_80 ;No
dec ax ;The last char of expansion
; is a special char. Do not
; include it in the insert
; string
@expand_fnkey_80:
push dx
call near ptr insert_at_dot ;Params SI,AX
; pushf ;Save CF
; call disp_line
; popf ;Restore CF
mov ax,1 ;AX<-exit code
pop dx ;DX is 0 if line is to be
; executed immediately
@expand_fnkey_99:
mov sp,bp
pop bp
@restore
ret
expand_fnkey endp
;+
; FUNCTION : store_char
;
; Stores the character in AX into the line buffer if max line
; length will not be exceeded. Characters may be inserted or
; overwrite chars in the buffer depending on the edit mode and whether
; auto-recall is on.
;
; Parameters:
; AX = character
;
; Returns:
; CF = 0 if no error, else 1
; Register(s) destroyed:
; <TBA>
;-
store_char proc near
@save si
cmp ax,256 ;char >= 256
jnb @store_char_90 ;Ignore if so
cmp edit_mode,0 ;1 if insert mode
je @store_char_20 ;Jump if overtype mode
cmp auto_recall_on,1 ;Is auto-recall on ?
je @store_char_20 ;Yes, behave as if in overtype mode
mov si,offset dgroup:tempchar ;temporary storage
mov [si],al ;Store char
mov ax,1 ;Length of string
call near ptr insert_at_dot ;Insert the character
jnc @store_char_99 ;No problemo
jmp short @store_char_90 ;No room in buffer
@store_char_20:
mov si,dot ;Current position in line
cmp si,LINEBUF_END ;At line end?
jae @store_char_90
; Enough room for a char
mov [si],al ;Store the char
mov dx,si ;DX->changed character
mov ax,si
inc ax ;AX->char after change
mov dot,ax ;Store it as new dot position
cmp si,lastchar ;Was it end of line ?
jb @store_char_30
mov lastchar,ax ;Store new end of line
@store_char_30:
call near ptr set_disp_marks ;ax,dx parameters
clc ;Indicate no error
jmp short @store_char_99
@store_char_90:
call near ptr bell
stc ;Indicate error
@store_char_99:
@restore
ret
store_char endp
;+
; FUNCTION : word_left
;
; Move one word left.
;
; Parameters:
; Globals linebuf and dot.
;
; Returns:
; CF = 1 if dot was at beginning of the line already
; 0 otherwise.
; Register(s) destroyed:
;-
word_left proc near
@word_left_10:
call near ptr char_left ;Move one char left
jc @word_left_99 ;Already at beginning of line
@word_left_12:
;Loop to backup over non-alphanum
call near ptr isalphnum ;AL alphanumeric?
jnc @word_left_15 ;Yes
call near ptr char_left ;One char left.
;AL<-char at dot
jnc @word_left_12 ;Not at beginning of line
@word_left_15: ;Now backup to beginning of word
; At this point, dot is always at a alphabetic char or beginning
; of the line
call near ptr char_left
jc @word_left_98 ;Were already at beginning of line
call near ptr isalphnum ;Alphanumeric?
jnc @word_left_15 ;Yes, loop back
;Found non-alphanumeric char
call near ptr char_right ;move over one
@word_left_98:
clc ;Clear carry flag
@word_left_99:
ret
word_left endp
;+
; FUNCTION : word_right
;
; Move one word right.
;
; Parameters:
; Globals linebuf and dot.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
word_right proc near
@word_right_10: ;Loop fwd over alphanumerics
call near ptr char_right ;One char right
;AL<-char at dot
jc @word_right_99 ;Already at end of line
call near ptr isalphnum ;Is AL alphanumeric ?
jnc @word_right_10 ;Yes, loop back
@word_right_15: ;Now move to beginning of word
call near ptr char_right
jc @word_right_99 ;Already at end of line
call near ptr isalphnum ;Alphanumeric?
jc @word_right_15 ;Not alphanum char, loop back
@word_right_99:
ret
word_right endp
;+
; FUNCTION : char_left
;
; Moves the 'dot' one character to the left unless
; already at the beginning of the line.
;
; Parameters:
; Global dot is current position in the line.
;
; Returns:
; AL = char at new dot position.
; CF = 1 if OLD dot was at beginning of line
; 0 otherwise.
; Register(s) destroyed:
;-
char_left proc near
@save si
mov ax,dot ;Current position in line
cmp ax,offset dgroup:linebuf
jne @char_left_5
stc ;Dot already at beginning of line
jmp short @char_left_99
@char_left_5:
dec ax ;Move dot left
mov dot,ax
@char_left_99:
xchg ax,si
lodsb ;AL<-char at dot
@restore
ret
char_left endp
;+
; FUNCTION : char_right
;
; Moves the 'dot' one character to the right unless
; already at the end of the line.
;
; Parameters:
; Global dot is current position in the line.
;
; Returns:
; AL = char at new dot position. Undefined if new dot is at
; the end of the line.
; CF = 1 if OLD dot was already at end of the line.
; 0 otherwise.
; Register(s) destroyed:
;-
char_right proc near
@save si
mov si,dot ;Current position in line
mov ax,lastchar ;AX->Beyond last char
dec ax ;AX->last char in line
cmp ax,si ;Dot at end ?
jc @char_right_99 ;Already at line end
inc si ;Move dot right, CF not affected
mov dot,si
lodsb ;AL<-char at dot, (undefined if
; dot is now at end of line).
; CF already clear
@char_right_99:
@restore
ret
char_right endp
;+
; FUNCTION : go_bol
;
; Sets dot to pint to the beginning of the line
;
; Register(s) destroyed: None.
;-
go_bol proc near
mov dot,offset dgroup:linebuf
ret
go_bol endp
;+
; FUNCTION : go_eol
;
; Sets dot to pint to the end of the line
;
; Register(s) destroyed: AX.
;-
go_eol proc near
mov ax,lastchar
mov dot,ax
ret
go_eol endp
;+
; FUNCTION : match_file
;
; match_file tries to expand the filename to the left of the
; cursor. If there are several matching files, the longest common
; prefix is placed on the line.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
match_file proc near
@save si,di
push bp
mov bp,sp
sub sp,64+44+2+2+2+2+2+2 ;Locals
pname equ 64 ;Storage for entire filename with path
ffblk equ pname+44
ffblk_attr equ ffblk-15h ;Attr byte within ffblk
ffblk_name equ ffblk-1Eh ;filename within ffblk
fname equ ffblk+2 ;Points to start of filename in name
oldDTAseg equ fname+2
oldDTAoff equ oldDTAseg+2
lineptr equ oldDTAoff+2 ;Pointer to location in linebuf
remaining equ lineptr+2 ;Remembers remaining space in path
breakstate equ remaining+2 ;Remembers break state
mov ax,3300h ;Get current break state
int 21h ;DL<-current break state
mov byte ptr [bp-breakstate],dl ;Remember it
xor dl,dl
mov ax,3301h ;Disable break check during
; disk i/O
int 21h
lea di,[bp-pname] ;OK 'cause SS==DS
mov si,dot ;Current line position
mov cx,63 ;Max length of path
@match_file_10:
cmp si,offset dgroup:linebuf
je @match_file_51 ;Beginning of line and filename
dec si
mov al,[si] ;AL<-next char
@match_file_25:
call near ptr isspace
je @match_file_50 ;Beginning of filename
@match_file_45: ;Check for next char if
; pathname not too long
loop @match_file_10
jmp @match_file_99 ;Pathname too long, just exit
@match_file_50:
inc si
@match_file_51:
; Copy filename into ASCIIZ buffer
; SI->first char of filename in path buffer
xor dx,dx ;Flags
mov ax,63
sub ax,cx ;Length of name
mov [bp-remaining],cx ;remember num bytes left in
; path buffer
xchg ax,cx ;CX<-length of name
mov [bp-lineptr],si ;Save start of path name in linebuf
mov [bp-fname],di ;Remember start of filename in
; path buffer as well (assumed)
or cx,cx ;Too far for jcxz
jne @match_file_55
jmp @match_file_99 ;No name, just exit
@match_file_55:
lodsb ;AL<-next char
stosb ;Store it
cmp al,'.'
jne @match_file_56
or dl,1 ;Set flag to remember file type '.'
jmp short @match_file_65 ;Check out next character
@match_file_56:
cmp al,'\' ;Directory separator?
jne @match_file_59
@match_file_57:
mov [bp-fname],di ;Update start of filename in
; path buffer
@match_file_58:
and dl,0FEh ;Forget file type flag
jmp short @match_file_65
@match_file_59:
cmp al,'/' ;Same thing
je @match_file_57
cmp al,':' ;Disk?
jne @match_file_65
and dl,0FEh ;Forget file type (shouldn't really
; occur)
mov [bp-fname],di ;Update start of filename in
; path buffer
@match_file_65:
loop @match_file_55
mov cx,[bp-remaining] ;CX<-remaining space
jcxz @match_file_52 ;Only space for terminator
mov al,'*'
stosb ;Attach a '*'
cmp cl,3 ;Enough space for ".*"
jb @match_file_52
and dl,1 ;Saw a file type ?
jne @match_file_52 ;Yes, go attach terminator
mov [di],2A2Eh ;Attach a ".*"
inc di
inc di
@match_file_52:
xor al,al ;AL<-0
stosb ;Terminating 0
; name contains the filename
push es
@GetDTA ;Get and save old DTA
mov [bp-oldDTAseg],es
mov [bp-oldDTAoff],bx
pop es
;
lea dx,[bp-ffblk]
@SetDTA dx ;Set DTA to our DTA
lea dx,[bp-pname] ;dx->ASCII name
@GetFirst dx,16 ;Include subdirs in search
jnc @match_file_70 ;No error
call near ptr bell ;No files found
jmp @match_file_90 ;Restore DTA and exit
@match_file_70: ;At least one file found
mov di,[bp-fname] ;DI->filename portion
lea si,[bp-ffblk_name] ;Name returned by GetFirst
@match_file_71: ;Copy the file name
lodsb
stosb
or al,al
jne @match_file_71
mov al,SPACE ;If file, add a space
test byte ptr [bp-ffblk_attr],16 ;Subdirectory?
je @match_file_72 ;No
mov al,'\' ;If subdir, add a backslash
@match_file_72:
mov byte ptr [di-1],al ;Add a space or a '\'
mov byte ptr [di],0
; Now hunt for more files. For each file found, keep the longest
; prefix in common so far.
@GetNext ;Get the next file name
jc @match_file_80 ;No more files
mov di,[bp-fname] ;DI->start of file name
lea si,[bp-ffblk_name] ;Name returned by GetNext
mov cx,13 ;Max Length of field
repe cmpsb ;Compare strings
mov byte ptr [di-1],0 ;Terminating null
jmp short @match_file_72 ;Try for more files
@match_file_80:
; Found one or more files, copy the longest common prefix
; into the line buffer
mov ax,[bp-lineptr] ;AX->start of chars to be deleted
call near ptr erase_to_dot ;Delete characters between dot
; and start of name
lea si,[bp-pname] ;SI->name to be copied
mov di,si
xor al,al
mov cx,64
repne scasb ;Hunt for terminating null
mov ax,63
sub ax,cx ;AX<-length of string
; SI->string, AX is length
push ax
call near ptr xlate_lower ;Convert to lowercase
pop ax
call near ptr insert_at_dot ;SI->source, AX == length
@match_file_90:
push ds
mov ds,[bp-oldDTAseg]
mov dx,[bp-oldDTAoff]
@SetDTA dx ;Restore DTA
pop ds
@match_file_99:
; Restore previous state of break checking
mov dl,byte ptr [bp-breakstate]
mov ax,3301h
int 21h
mov sp,bp
pop bp
@restore
ret
match_file endp
CSEG ENDS
END